#include "stdafx.h"
#include "random_gen.hpp"

// This is a reproducible simulation experiment.  See main().


/*void experiment(base_generator_type & generator)
{
  // Define a uniform random number distribution of integer values between
  // 1 and 6 inclusive.
  typedef boost::uniform_int<> distribution_type;
  typedef boost::variate_generator<base_generator_type&, distribution_type> gen_type;
  gen_type die_gen(generator, distribution_type(1, 6));

#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530)
  // If you want to use an STL iterator interface, use iterator_adaptors.hpp.
  // Unfortunately, this doesn't work on SunCC yet.
  boost::generator_iterator<gen_type> die(&die_gen);
  for(int i = 0; i < 10; i++)
    std::cout << *die++ << " ";
  std::cout << '\n';
#endif
}*/


generator::generator(const char* _filename): 
	_status_file(_filename), 
	_min_distr_value(0x21), 
	_max_distr_value(0x7E), 
	_generator(42u) 
{
	init_experiment();
}	

generator::generator(unsigned short min_distr_value, 
					unsigned short max_distr_value, 
					 const std::string& _filename): 
	_status_file(_filename), 
	_min_distr_value(min_distr_value), 
	_max_distr_value(max_distr_value), 
	_generator(42u) 
{
	init_experiment();
}	


  	// You can save a generator's state by copy construction.
generator& generator::operator=(const generator& generator)
{
	_generator = generator._generator;
	_die_gen = generator._die_gen;
	_die = generator._die;
	_min_distr_value = generator._min_distr_value;
	_max_distr_value = generator._max_distr_value;

	return *this;
}

void generator::pack()
{
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE

	// You can save the generator state for future use.  You can read the
	// state back in at any later time using operator>>.

    	std::ofstream file(_status_file.c_str(), std::ofstream::trunc);
    	file << _generator;
#endif
}

bool generator::unpack()
{
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
	std::ifstream file(_status_file.c_str(), std::ifstream::trunc);
	if(file.good())
	{
		file >> _generator;
		file.close();
		return true;
	}
#endif	
	return false;	
}


// This is a reproducible simulation experiment.  See main().
void generator::init_experiment()
{
	// Change seed to something else.
	//
	// Caveat: std::time(0) is not a very good truly-random seed.  When
	// called in rapid succession, it could return the same values, and
	// thus the same random number sequences could ensue.  If not the same
	// values are returned, the values differ only slightly in the
	// lowest bits.  A linear congruential generator with a small factor
	// wrapped in a uniform_smallint (see experiment) will produce the same
	// values for the first few iterations.   This is because uniform_smallint
	// takes only the highest bits of the generator, and the generator itself
	// needs a few iterations to spread the initial entropy from the lowest bits
	// to the whole state.
	//

	_generator.seed(static_cast<unsigned int>(std::time(0)));

	// Define a uniform random number distribution of integer values between
	// _min_distr_value and _max_distr_value inclusive.
//	std::cout << "min distribution value = "<< _min_distr_value<< std::endl;
//	std::cout << "max disribution value = " << _max_distr_value << std::endl;

	_die_gen = new gen_type(_generator, distribution_type(_min_distr_value, _max_distr_value)); 

#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530)
	// If you want to use an STL iterator interface, use iterator_adaptors.hpp.
	// Unfortunately, this doesn't work on SunCC yet.
	boost::generator_iterator<gen_type> die(_die_gen);
                
	_die = die;		
	std::cout.setf(std::ios::fixed);
//  		for(int i = 0; i < 10; i++)
//    			std::cout << *_die++ << " ";
//  		std::cout << '\n';
#endif
}


generator::~generator() { delete _die_gen; }
 	
